package thread;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: LYW
 * Date: 2025-05-27
 * Time: 21:13
 */
//自己实现阻塞队列并用于生产消费者模型
class MyBlockingQueue {

    private String[] data = null;

    //队列首
    private int head = 0;

    //队列尾
    private int tail = 0;

    //元素个数
    private int size = 0;

    public MyBlockingQueue (int capacity) {
        data = new String[capacity];
    }

    public void put(String elem) throws InterruptedException {
        synchronized (this) {
            while (size >= data.length) {
                //队列满了 阻塞
                this.wait();//wait之前判断一次 唤醒也判定一次
            }
            data[tail] = elem;
            tail++;
            if (tail >= data.length) {
                tail = 0;
            }
            //tail = (tail + 1) % data.length; //与上面四行代码逻辑相同
            size++;
            this.notify();//唤醒take的wait(size++队列不为空)
        }
    }

    public String take() throws InterruptedException {
        synchronized (this) {
            /**
             * 如果只是一个线程take 一个线程put不会出现不会出现自己唤醒自己的情况
             * 多个线程take 多个线程put 确实有自己唤醒自己的风险 但是用过while循环条件避免这样的影响
             * while也能在interrupt中断的情况下还能继续让其等待 不会出现size = - 1的情况
             */
            while (size == 0){
                //队列空了 需要阻塞
                this.wait();//wait之前判断一次 唤醒也判定一次
            }
            String ret = data[head];
            head++;
            if (head >= data.length) {
                head = 0;
            }
            //head = (head + 1) % data.length;
            size--;
            this.notify();//唤醒put的wait(size--队列就不满了)
            return ret;
        }
    }
    /**
     * 比如有若干个线程用这个队列
     * 要么所有阻塞在put 要么 take
     * 不可能出现一些阻塞在put 一些阻塞在take (因为队列不可能是既满又空)
     */
}
public class Demo31 {
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue(100);

        Thread producer = new Thread(() -> {
            int n =0;
            while (true) {
                try {
                    queue.put(n + "");
                    System.out.println("生产元素：" + n);
                    //Thread.sleep(1000);
                    n++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });

        Thread consumer = new Thread(() -> {
           while (true) {
               try {
                   String n = queue.take();
                   System.out.println("消费元素：" + n);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });

        producer.start();
        consumer.start();

    }
}
